package diploma.main;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import diploma.matrika.MatrikaParov;
import diploma.matrika.MatrikaParov.eTipRazdalje;
import diploma.matrika.data.Par;
import diploma.substitucija.Buffer;
import diploma.substitucija.Substitucija;
import diploma.tokenizer.Tokenizer;
import diploma.vizualizacija.Vizualizacija;
import static java.lang.System.*;
/*
 * Ta razred bo prebral Slovar in besedilo in ju bo naložil 
 * v pomnilnik.
 * 
 * Nato bo zgeneriral naključno permutacijo in
 * iz besedila naredil premešanko :)
 * 
 * Iz slovarja in premešanega besedila bo še izračunal
 * frekvence parov. 
 * 
 *  Izpostavil metode za izračun razdalje med dvema 
 *  matrikama.

 */
public class TestSlovarBesedilo
{
        File slovar;
        File besedilo;
        List<String> lstBesedeSlovarja;
        List<String> lstBesedeBesedila;
        List<String> lstBesedePremešanegaBesedila;
        StringBuffer sbOriginalnoBesedilo;
        StringBuffer sbPremešanoBesedilo;
        MatrikaParov matSlovar;
        MatrikaParov matBesedilo;
        MatrikaParov matPremešanoBesedilo;
        Substitucija subUporabljena;
        List<Par> lstMaxParovSlovarja;
        List<Par> lstMaxParovBesedila;
        List<Par> lstMaxParovPremešanegaBesedila;
        
        public int numMaxParov;
        
        public TestSlovarBesedilo(File slovar, File besedilo) throws FileNotFoundException
        {
                this.slovar = slovar;
                this.besedilo = besedilo;
                StringBuffer sbSlovar = Buffer.file2Buffer(slovar);
                sbOriginalnoBesedilo = Buffer.file2Buffer(besedilo);
                lstBesedeSlovarja = Tokenizer.bufferToList(sbSlovar);
                lstBesedeBesedila = Tokenizer.bufferToList(sbOriginalnoBesedilo);
                subUporabljena = new Substitucija();
                matSlovar = new MatrikaParov();
                matBesedilo = new MatrikaParov();
                matPremešanoBesedilo = new MatrikaParov();
                matSlovar.posodobiFrekvence(lstBesedeSlovarja);
                //Izračunamo statistiko pojavljanja črk
                lstBesedeSlovarja = null; //Da sprosti pomnilnik, ker ga ne rabimo več!
                matBesedilo.posodobiFrekvence(lstBesedeBesedila);
                sbPremešanoBesedilo = subUporabljena.naključnaSubstitucija(sbOriginalnoBesedilo);
                lstBesedePremešanegaBesedila = Tokenizer.bufferToList(sbPremešanoBesedilo);
                matPremešanoBesedilo.posodobiFrekvence(lstBesedePremešanegaBesedila);
        }

        
        public List<String> lstNoveBesede;
        
        /**
         * Izbere window besed iz kombajna velikosti numBesed.
         * Window je zmeraj izbran iz nakljične lokacije.
         * 
         * 
         */
        public void generirajNaključnoBesedilo(int numBesed)
        {
                int index = (int)Math.max(Math.random()*lstBesedeBesedila.size() - numBesed, 0);
                lstNoveBesede = new ArrayList<>();
                for(int i = index; i < index + numBesed; i++)
                {
                        lstNoveBesede.add(lstBesedeBesedila.get(i));
                }
                matBesedilo = new MatrikaParov();
                matBesedilo.posodobiFrekvence(lstNoveBesede);
                
        }
        
        
        public void ponovnoPremešaj() 
        
        //u resnic sm meša in govori substituciji, kaj se dogaja, da bo vedla kaka je 
        //ne ustvarja vedno nove substitucije in potlej matrike, ker bi blo prevec potratno 
        
        {
                matPremešanoBesedilo = matBesedilo.clone();
                subUporabljena.reset();
                for(int i = 0; i < MatrikaParov.MAX_PAROV; i++) //Po vseh stolpcih
                {
                        int indexNakljućnegaStolpca1 = Math.max((int)Math.floor(Math.random()*MatrikaParov.MAX_PAROV), 1) ;  //ce pride manj kot ena, da prvo vzame
                        int indexNaključnegaStolpca2 = Math.max((int)Math.floor(Math.random()*MatrikaParov.MAX_PAROV), 1) ;
                        matPremešanoBesedilo.permutacija(indexNakljućnegaStolpca1, indexNaključnegaStolpca2);
                        subUporabljena.narediZamenjavo(indexNakljućnegaStolpca1, indexNaključnegaStolpca2);
                }
        }
        
        public List<String> getLstBesedeSlovarja()                                              { return lstBesedeSlovarja;}
        public List<String> getLstBesedeBesedila()                                              { return lstBesedeBesedila; }
        public List<String> getLStBesedePremešanegaBesedila()                  					{ return lstBesedePremešanegaBesedila;  } 
        public StringBuffer getOriginalnoBesedilo()                                  		    { return sbOriginalnoBesedilo; }
        public StringBuffer getPremešanoBesedilo()                                              { return sbPremešanoBesedilo; }
        public MatrikaParov getMatSlovar()                                                      { return matSlovar;}
        public MatrikaParov getMatBesedilo()                                                    { return matBesedilo; }
        public MatrikaParov getMatPremešanoBesedilo()                                   		{ return matPremešanoBesedilo; }
        public Substitucija getSubZaPremešanoBesedila()                                 		{ return subUporabljena; }
        public List<Par>    getMaxParovSlovarja()                                     		    { return lstMaxParovSlovarja; }
        public List<Par>    getMaxParovBesedila()                                     		    { return lstMaxParovBesedila; }
        public List<Par>    getMaxParovPremešanegaBesedila()                  		     		{ return lstMaxParovPremešanegaBesedila; }
        
        
        public double razlikaMedBesedilomInSlovarjem(eTipRazdalje tip)
        {
                return matSlovar.razdalja(matBesedilo, tip);
        }
        
        public double razlikaMedBesedilomInŠifriranimBesedilom(eTipRazdalje tip)
        {
                return matBesedilo.razdalja(matPremešanoBesedilo, tip);
        }
        
        public double razlikaMedSlovarjemInŠifriranimBesedilom(eTipRazdalje tip)
        {
                return matSlovar.razdalja(matPremešanoBesedilo, tip);
        }
        
        public static void main(String[] args) throws FileNotFoundException, InvocationTargetException, InterruptedException
        {
                List<SolveCandidat2> listaResitev = new ArrayList<>();
                out.print("Inicializacija...");
                TestSlovarBesedilo testAlgoritma = new TestSlovarBesedilo(new File("slovar-sl.txt"), new File("manjsi3-si.txt"));
                final int ST_TESTOV = 20;
                System.out.println("Št besed v vzorcu: " + testAlgoritma.lstBesedeBesedila.size() );
                for(int i = 0; i < ST_TESTOV; i++)
                {
                        testAlgoritma.ponovnoPremešaj();
                        SolveCandidat2 solve = solve2(testAlgoritma, i, eTipRazdalje.manhattan, 8);
                        listaResitev.add(solve);

                        System.out.println("**Permutacija premešanega besedila");;
                        testAlgoritma.subUporabljena.izpisiSubstitucijo();

                        System.out.println("**Permutacija rešitve");
                        solve.getSubstitucijoResitve().izpisiInverznoSubstitucijo();
                        System.out.println("Št različnih: " + solve.getSubstitucijoResitve().razlikaInvert(testAlgoritma.subUporabljena));
                }
                izpisInformacij(testAlgoritma);
        }
        
        private static void izpisInformacij(TestSlovarBesedilo testAlgoritma)
        {
                out.println("Končana");
                out.println(String.format("Razlike: [%s,%s,%s]",eTipRazdalje.evklidska.name(), eTipRazdalje.manhattan.name(), eTipRazdalje.maximum.name()));
                out.print("\tbesediloInSlovar:");
                        out.print(testAlgoritma.razlikaMedBesedilomInSlovarjem(eTipRazdalje.evklidska)+",");
                        out.print(testAlgoritma.razlikaMedBesedilomInSlovarjem(eTipRazdalje.manhattan)+",");
                        out.println(testAlgoritma.razlikaMedBesedilomInSlovarjem(eTipRazdalje.maximum));
                out.print("\tbesediloInSifriranTekst:");
                        out.print(testAlgoritma.razlikaMedBesedilomInŠifriranimBesedilom(eTipRazdalje.evklidska)+",");
                        out.print(testAlgoritma.razlikaMedBesedilomInŠifriranimBesedilom(eTipRazdalje.manhattan)+",");
                        out.println(testAlgoritma.razlikaMedBesedilomInŠifriranimBesedilom(eTipRazdalje.maximum));
                out.print("\tslovarInSifriranTekst:");
                        out.print(testAlgoritma.razlikaMedSlovarjemInŠifriranimBesedilom(eTipRazdalje.evklidska)+",");
                        out.print(testAlgoritma.razlikaMedSlovarjemInŠifriranimBesedilom(eTipRazdalje.manhattan)+",");
                        out.println(testAlgoritma.razlikaMedSlovarjemInŠifriranimBesedilom(eTipRazdalje.maximum));
                        
                
                System.out.println("Tabela seštevka stolpcev");
                System.out.print("SLOV: ");
                for(int i = 1; i < MatrikaParov.MAX_PAROV; i++)
                {
                        System.out.print(" " + MatrikaParov.getCharacter(i) + " " + testAlgoritma.getMatSlovar().sestejStolpec(i));
                }
                System.out.println();
                System.out.print("BESE: ");
                for(int i = 1; i < MatrikaParov.MAX_PAROV; i++)
                {
                        System.out.print(" " + MatrikaParov.getCharacter(i) + " " + testAlgoritma.getMatBesedilo().sestejStolpec(i));
                }
                System.out.println();
                System.out.print("SIFR: ");
                for(int i = 1; i < MatrikaParov.MAX_PAROV; i++)
                {
                        System.out.print(" " + MatrikaParov.getCharacter(i) + " " + testAlgoritma.getMatPremešanoBesedilo().sestejStolpec(i));
                }
                System.out.println();

                System.out.println("Permutacija šifriranega besedila");
                testAlgoritma.subUporabljena.izpisiSubstitucijo();
                
        }

        private static  SolveCandidat2 solve2(TestSlovarBesedilo test, long iter, eTipRazdalje razdalja, int maxN)
        {
                SolveCandidat2 solve2 = new SolveCandidat2(test.getMatSlovar(), test.getMatPremešanoBesedilo().clone(), razdalja, maxN);   
                solve2.doSolve();
                double razlika = solve2.getMatrikoDešifriranega().razdalja(test.matBesedilo, razdalja);
                System.out.println("Resitev["+iter+"]: " + solve2.getRazlikaResitveSSlovarjem() + " St. iteracij: " + solve2.getŠteviloIteracij() + " Je uspesno? = " + razlika );
          
                return solve2;
        }
        
       
        
}
